package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
)

// 加载服务器配置文件
func loadConfig() {
	// 获取可执行文件所在目录  ./config.json
	exePath, _ := os.Executable()
	exeDir := filepath.Dir(exePath)
	configFileTemp, err := os.Open(exeDir + "/config.json")
	if err != nil {
		panic("file \"./config.json\" not found")
	}
	//函数退出时关闭文件流
	defer func(configFile *os.File) {
		_ = configFile.Close()
	}(configFileTemp)
	//解析json
	decoder := json.NewDecoder(configFileTemp)
	err = decoder.Decode(&configFile)
	if err != nil {
		panic("config format err")
	}
}

// 初始化Gin引擎
func initGinEngine() {
	// 设置gin模式为发布模式
	gin.SetMode(gin.ReleaseMode)
	//关闭gin日志输出  自认为小项目没什么用
	gin.DefaultWriter = io.Discard
	// 创建Gin引擎
	copilotGinEngine = gin.New()
	// 设置信任的前置代理  用nginx反代需要  不写这个编译会有个警告看着难受
	if err := copilotGinEngine.SetTrustedProxies([]string{"127.0.0.1"}); err != nil {
		log.Fatal(err)
	}
}

// StartServer 启动服务器并监听ip和端口
func StartServer() {
	//监听地址是host+port
	listenAddress := configFile.Server.Host + ":" + strconv.Itoa(configFile.Server.Port)
	server := &http.Server{
		Addr: listenAddress,
		TLSConfig: &tls.Config{
			NextProtos: []string{"http/1.1", "http/1.2", "http/2"},
		},
		Handler: copilotGinEngine,
	}
	go func() {
		if configFile.Server.Port != 443 {
			err := copilotGinEngine.Run(listenAddress)
			log.Fatal(err)
		} else {
			err := server.ListenAndServeTLS(configFile.Server.CertPath, configFile.Server.KeyPath)
			log.Fatal(err)
		}
	}()
}

// 自定义请求失败返回的状态码和错误信息
func diyBadRequest(c *gin.Context, code int, errorMessage string) {
	c.JSON(code, gin.H{
		"message":           errorMessage,
		"documentation_url": "https://docs.github.com/rest",
	})
}

// registerProxyRoute 反向代理路由
func registerProxyRoute(r *gin.Engine, routePath, targetURL string) {
	target, _ := url.Parse(targetURL)
	isModMsgEnabled := configFile.IsModMsg && targetURL == completionUrl
	director := func(req *http.Request) {
		req.URL.Host = target.Host
		req.Host = target.Host
		req.URL.Scheme = "https"
	}
	proxy := &httputil.ReverseProxy{
		Director:     director,
		ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {},
	}
	r.Any(routePath, func(c *gin.Context) {
		if isModMsgEnabled {
			modProxyResp(c)
		} else {
			proxy.ServeHTTP(c.Writer, c.Request)
		}
	})
}

func modProxyResp(c *gin.Context) {
	c.Header("Content-Type", "text/plain;charset=utf-8")
	c.Header("X-Forwarded-Proto", "http")
	runes := []rune(configFile.DiyMsg)
	for _, r := range runes {
		modStr := fmt.Sprintf("data: {\"id\":\"cmpl-7xy1GLgssjHEubVrPyt534VRYVF0t\",\"model\":\"cushman-ml\",\"created\":1694526422,\"choices\":[{\"text\":\"%c\",\"index\":0,\"finish_reason\":null,\"logprobs\":null}]}\n", r)
		c.String(200, modStr)
	}
	c.String(200, "data: [DONE]\n")
}
